home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / CRIBBAGE.PAK / CRIBBAGE.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  41KB  |  1,396 lines

  1. //--------------------------------------------------------------------------
  2. // Turbo Cribbage -- Copyright (c) 1995, Borland International
  3. //--------------------------------------------------------------------------
  4. #include <owl/pch.h>
  5. #include <owl/applicat.h>
  6. #include <owl/framewin.h>
  7. #include <owl/window.h>
  8. #include <owl/inputdia.h>
  9.  
  10. #include "cribbage.h"       // declaration of TGameWindow
  11. #include "board.h"          // TCribbageBoard
  12. #include "cards.h"          // TCard, TCardGroup, TDeck
  13. #include "carddisp.h"       // TCardDisplay
  14. #include "dialogs.h"        // TCutDeckDialog, TCutResultDialog,
  15.                             // TShowPointsDialog, TQuickPointsDialog
  16.                             // TGoDialog
  17.  
  18. #include "cribbage.rh"
  19.  
  20. const char IniFilename[] = "CRIBBAGE.INI";
  21. const int NAME_LEN = 21;
  22.  
  23. char playerName[NAME_LEN];
  24.  
  25. // the following arrays hold the card positions for the various
  26. // card displays used in the game
  27.  
  28. TPoint TGameWindow::handCardPos[6] =
  29.            { TPoint(20,20), TPoint(35,20), TPoint(50,20),
  30.              TPoint(65,20), TPoint(80,20), TPoint(95,20) };
  31.  
  32. TPoint TGameWindow::cribCardPos[4] =
  33.            { TPoint(20,20), TPoint(35,20),
  34.              TPoint(50,20), TPoint(65,20) };
  35.  
  36. TPoint TGameWindow::pegCardPos[8] =
  37.            { TPoint(20,0), TPoint(35,0), TPoint(50,0), TPoint(65,0),
  38.              TPoint(80,0), TPoint(95,0), TPoint(110,0), TPoint(125,0) };
  39.  
  40. TPoint TGameWindow::topCardPos[1] = { TPoint(0,0) };
  41.  
  42. DEFINE_RESPONSE_TABLE1(TGameWindow, TWindow)
  43.   EV_COMMAND(CM_GAME_NEW, NewGame),
  44.   EV_COMMAND(CM_GAME_EXIT, Exit),
  45.   EV_COMMAND(CM_HELP_ABOUT, AboutBox),
  46.   EV_MESSAGE(WM_CARD_SELECTED, CardSelected),
  47.   EV_COMMAND(CM_GO_BUTTON, GoButton),
  48.   EV_COMMAND(CM_DONE_BUTTON, DoneButton),
  49.   EV_COMMAND(CM_DEAL_BUTTON, DealButton),
  50. END_RESPONSE_TABLE;
  51.  
  52. // RunSize -- determines if the given cards form a run, and if they
  53. // do, returns the size of the run.  This only detects single runs.
  54. // this function is used to test subsets of cards from the hand.
  55. //
  56. int TGameWindow::RunSize(int *rank, int count) {
  57.   int largestRun,i;
  58.   int hittest[13];
  59.   int currentValue,transitionCount;
  60.  
  61.   // must have at least 3 cards for a run
  62.  
  63.   if (count<3)
  64.     return 0;
  65.  
  66.   // first, create a size 13 array (1 position for each card rank),
  67.   // and fill it with zeros.  Then loop through all the cards, and
  68.   // increment the position in the array for each card rank encountered.
  69.   // then loop through the array and count how many transitions there
  70.   // are.  If there are 2 or less transitions, then there is a run.
  71.   // Also, if any value of the hittest array is >1, then there is no
  72.   // run.
  73.   //
  74.   // here's a few examples:
  75.   //
  76.   //  cards                           hittest array
  77.   // -----------------------------------------------------------
  78.   //  3,4,5,5,9                      0 0 1 1 2 0 0 0 1 0 0 0 0
  79.   //                                    ^   ^ ^     ^ ^
  80.   //                                      5 transitions
  81.   //
  82.   //  4,5,6,7,8                      0 0 0 1 1 1 1 1 0 0 0 0 0
  83.   //                                      ^         ^
  84.   //                                      2 transitions
  85.   //
  86.   //  7,7,8,8                        0 0 0 0 0 0 2 2 0 0 0 0 0
  87.   //                                            ^   ^
  88.   //                                          2 transitions
  89.  
  90.   largestRun=0;
  91.  
  92.   for (i=0;i<13;i++)
  93.     hittest[i]=0;
  94.  
  95.   // fill the hittest array
  96.  
  97.   for (i=0;i<count;i++)
  98.     hittest[rank[i]-1]++;
  99.  
  100.   // count the # of transitions
  101.  
  102.   currentValue=0;
  103.   transitionCount=0;
  104.   for (i=0;i<13;i++) {
  105.     if (hittest[i]!=currentValue) {
  106.       transitionCount++;
  107.       currentValue=hittest[i];
  108.  
  109.       // if the value in the hittest array is >1, then there cannot
  110.       // be a run, so force the transitionCount value high enough
  111.       // that we don't count a run.
  112.  
  113.       if (currentValue>1)
  114.         transitionCount=5;
  115.     }
  116.   }
  117.   if (transitionCount<=2)
  118.     largestRun = count;
  119.  
  120.   assert((largestRun==0) || (largestRun>=3));
  121.  
  122.   return largestRun;
  123. }
  124.  
  125. // ComputeHandPoints -- computes the points in a hand (either a normal
  126. // hand or the crib).  It returns the points counted, and also computes
  127. // a detailed list of the points counted
  128. //
  129. int TGameWindow::ComputeHandPoints(TCardGroup* cards, TCard* extraCard,
  130.                                     BOOL crib) {
  131.  
  132.  
  133.   int rank[5];         // rank of the cards (1-13)
  134.   int faceValue[5];    // face value of cards (1-10) (10,J,Q,K all = 10)
  135.   int suit[5];         // suit of each card
  136.   int runrank[5],
  137.       runcardcount,
  138.       runs[6];         // used to count 3,4,5 card runs
  139.  
  140.   int i,j,fifteenCount,pairCount,runSize,size,
  141.       runCount,sum,temp,flushSize,matchingJack,total,largestRun;
  142.  
  143.   char tempstr[20];
  144.  
  145.   // initialize the faceValue, rank, and suit arrays
  146.  
  147.   for (i=0;i<4;i++) {
  148.     rank[i]=(*cards)[i].rank;
  149.     faceValue[i]=FaceValue(rank[i]);
  150.     suit[i] = (*cards)[i].suit;
  151.   }
  152.  
  153.   rank[4] = extraCard->rank;
  154.   faceValue[4]=FaceValue(rank[4]);
  155.   suit[4] = extraCard->suit;
  156.  
  157.   flushSize=0;
  158.   fifteenCount=0;
  159.   pairCount=0;
  160.   matchingJack=0;
  161.   runSize=0;
  162.   runCount=0;
  163.   runs[3]=0;
  164.   runs[4]=0;
  165.   runs[5]=0;
  166.  
  167.   detailCount=0;
  168.  
  169.   // check for all combinations of cards that add to 15
  170.  
  171.   for (i=1;i<32;i++) {
  172.     sum=0;
  173.     temp=i;
  174.  
  175.     detail[detailCount][0]=0;
  176.  
  177.     // loop through all bits of i
  178.     for (j=0;j<5;j++) {
  179.  
  180.       // if the bit is set, add that card into the sum.
  181.  
  182.       if (temp&1) {
  183.         strcat(detail[detailCount],TCard::Stringify(rank[j],suit[j]));
  184.         strcat(detail[detailCount]," ");
  185.         sum=sum+faceValue[j];
  186.       }
  187.  
  188.       // get next bit
  189.       temp=temp/2;
  190.     }
  191.  
  192.     if (sum==15) {
  193.       fifteenCount++;
  194.       strcat(detail[detailCount++],"\t(fifteen)\t2 pts");
  195.     }
  196.   }
  197.  
  198.   // first find out what the largest run size is
  199.  
  200.   largestRun=0;
  201.   for (i=1;i<32;i++) {
  202.     temp=i;
  203.     runcardcount=0;
  204.     for (j=0;j<5;j++) {
  205.       if (temp&1)
  206.         runrank[runcardcount++]=rank[j];
  207.       temp=temp/2;
  208.     }
  209.  
  210.     size = RunSize(runrank, runcardcount);
  211.     if (size>largestRun)
  212.       largestRun=size;
  213.   }
  214.  
  215.   // now go back and re-check for runs, but ignore anything
  216.   // smaller than the largest run found above
  217.  
  218.   if (largestRun>=3) {
  219.     for (i=1;i<32;i++) {
  220.       temp=i;
  221.       runcardcount=0;
  222.  
  223.       detail[detailCount][0]=0;
  224.       // loop through all bits of i
  225.       for (j=0;j<5;j++) {
  226.         if (temp&1) {
  227.           runrank[runcardcount++]=rank[j];
  228.           strcat(detail[detailCount],TCard::Stringify(rank[j],suit[j]));
  229.           strcat(detail[detailCount]," ");
  230.         }
  231.         temp=temp/2;
  232.       }
  233.  
  234.       size = RunSize(runrank, runcardcount);
  235.       if (size==largestRun) {
  236.         runCount++;
  237.         wsprintf(tempstr,"\t(%d-card run)\t%d pts",size,size);
  238.         strcat(detail[detailCount++],tempstr);
  239.       }
  240.     }
  241.     // only count the largest run.  ie, a 4-card run doesn't
  242.     // also count as 2 3-card runs.
  243.  
  244.     runSize=largestRun;
  245.   }
  246.  
  247.   // count pairs.  Note that this loop skips the condition where
  248.   // i=j, and only counts each pair once (ie, it doesn't look at
  249.   // the combination i=2,j=3 and i=3,j=2, since that would count
  250.   // the same combination twice)
  251.  
  252.   for (i=0;i<5;i++)
  253.     for (j=i+1;j<5;j++)
  254.       if (rank[i]==rank[j]) {
  255.         pairCount++;
  256.         strcpy(detail[detailCount],TCard::Stringify(rank[i],suit[i]));
  257.         strcat(detail[detailCount]," ");
  258.         strcat(detail[detailCount],TCard::Stringify(rank[j],suit[j]));
  259.         strcat(detail[detailCount++],"\t(pair)\t2 pts");
  260.       }
  261.  
  262.   // check for flushes
  263.  
  264.   if ((suit[0]==suit[1]) &&
  265.       (suit[1]==suit[2]) &&
  266.       (suit[2]==suit[3])) {
  267.     flushSize=4;
  268.     if ((!crib) && (suit[3]==suit[4]))
  269.       flushSize++;
  270.   }
  271.  
  272.   if (flushSize) {
  273.     detail[detailCount][0]=0;
  274.     for (i=0;i<flushSize;i++)
  275.       if (suit[i]==suit[0]) {
  276.         strcat(detail[detailCount],TCard::Stringify(rank[i],suit[i]));
  277.         strcat(detail[detailCount]," ");
  278.       }
  279.     wsprintf(tempstr,"\t(%d-card flush)\t%d pts",flushSize,flushSize);
  280.     strcat(detail[detailCount++],tempstr);
  281.   }
  282.  
  283.   // check for nobs
  284.  
  285.   for (i=0;i<4;i++)
  286.     if ((rank[i]==11) &&
  287.         (suit[i]==suit[4])) {
  288.       matchingJack=1;
  289.       wsprintf(detail[detailCount++],"%s%s\t(nobs)\t1 pt",
  290.                 TCard::Stringify(rank[i], suit[i]));
  291.     }
  292.  
  293.  
  294.   total = fifteenCount*2 +     // 2 points for each 15
  295.           pairCount*2 +        // 2 points for each pair
  296.           runSize*runCount +   // N points for each N-card run
  297.           flushSize +          // 4 or 5 points for a 4 or 5 card flush
  298.           matchingJack;        // 1 point for a jack of the same suit as
  299.  
  300.   strcpy(detail[detailCount++],"----------------------------------------------------");
  301.   wsprintf(detail[detailCount++],"\tTotal:\t%d",total);
  302.  
  303.   return total;
  304. }
  305.  
  306. BOOL TGameWindow::GameOver() {
  307.   if ((board->GetScore(0)==121) ||
  308.       (board->GetScore(1)==121))
  309.     return true;
  310.   return false;
  311. }
  312.  
  313. // ShowPoints -- after all cards have been played, this function
  314. // is called to split the cards back into their respective hands,
  315. // and count the points for each hand.  The hands are counted in
  316. // the following order:  nondealer, dealer, crib.
  317. //
  318. void TGameWindow::ShowPoints() {
  319.   int  points,actualPoints;
  320.  
  321.   // split the cards back into two hands
  322.  
  323.   ReclaimPegCards();
  324.   instructions->SetText("");
  325.  
  326.   for (int i=0;i<crib->GetCount();i++)
  327.     crib->FaceUp(i, true);
  328.  
  329.   // NOTE: the AddToScore function returns true if players score
  330.   // exceeds 121.  Any time we call AddToScore, if the return value
  331.   // is true, the game is over so we simply return from this function.
  332.  
  333.   if (dealer==1) {
  334.  
  335.     // player dealt, let computer show points first, then
  336.     // let the player count their hand, and then the crib.
  337.  
  338.     points = ComputeHandPoints(player[0], &((*topCard)[0]), false);
  339.     TShowPointsDialog(this, TShowPointsDialog::mtHand,
  340.                        points, 0, detail, detailCount).Execute();
  341.     if (board->AddToScore(0, points)) return;
  342.  
  343.     actualPoints = ComputeHandPoints(player[1], &((*topCard)[0]), false);
  344.     points = TQuickPointsDialog(this,
  345.                                 "Enter the points you count in your hand",
  346.                                false, actualPoints).Execute();
  347.     if (board->AddToScore(1, points)) return;
  348.     if (points<actualPoints) {
  349.       TShowPointsDialog(this, TShowPointsDialog::mtMissed,
  350.                          points, actualPoints-points, detail, detailCount).Execute();
  351.       if (board->AddToScore(0, actualPoints-points)) return;
  352.     }
  353.  
  354.     actualPoints = ComputeHandPoints(crib, &((*topCard)[0]), true);
  355.     points = TQuickPointsDialog(this,
  356.                                  "Enter the points you count in the crib",
  357.                                  false, actualPoints).Execute();
  358.     if (board->AddToScore(1, points)) return;
  359.     if (points<actualPoints) {
  360.       TShowPointsDialog(this, TShowPointsDialog::mtMissed,
  361.                          points, actualPoints-points, detail, detailCount).Execute();
  362.       if (board->AddToScore(0, actualPoints-points)) return;
  363.     }
  364.  
  365.   } else {
  366.  
  367.     // computer dealt, let player count their hand first, then
  368.     // count computers hand and crib.
  369.  
  370.     actualPoints = ComputeHandPoints(player[1], &((*topCard)[0]), false);
  371.     points = TQuickPointsDialog(this,
  372.                                  "Enter the points you count in your hand",
  373.                                  false, actualPoints).Execute();
  374.     if (board->AddToScore(1, points)) return;
  375.     if (points<actualPoints) {
  376.       TShowPointsDialog(this, TShowPointsDialog::mtMissed,
  377.                          points, actualPoints-points, detail, detailCount).Execute();
  378.       if (board->AddToScore(0, actualPoints-points)) return;
  379.     }
  380.  
  381.     points = ComputeHandPoints(player[0], &((*topCard)[0]), false);
  382.     TShowPointsDialog(this, TShowPointsDialog::mtHand,
  383.                        points, 0, detail, detailCount).Execute();
  384.     if (board->AddToScore(0, points)) return;
  385.  
  386.     points = ComputeHandPoints(crib, &((*topCard)[0]), true);
  387.     TShowPointsDialog(this, TShowPointsDialog::mtCrib,
  388.                        points, 0, detail, detailCount).Execute();
  389.     if (board->AddToScore(0, points)) return;
  390.   }
  391. }
  392.  
  393. // ResetPegCardDisplay -- blanks out the peg card count, and resets
  394. // the array which keeps track of the peg cards owner
  395. //
  396. void TGameWindow::ResetPegCardDisplay() {
  397.   int i;
  398.  
  399.   pegCards->SetLabel("");
  400.   for (i=0;i<8;i++)
  401.     pegCardOwner[i]=-1;
  402. }
  403.  
  404. // ReclaimPegCards -- move the cards from the pegdisplay back into
  405. // the computer and player hands.  The pegCardOwner array keeps track
  406. // of which hands the cards came from.
  407. //
  408. void TGameWindow::ReclaimPegCards() {
  409.   int i;
  410.   for (i=0;i<8;i++)
  411.     player[pegCardOwner[i]]->Insert(pegCards->Remove(), true);
  412.   ResetPegCardDisplay();
  413. }
  414.  
  415.  
  416. void TGameWindow::SetState(TGameState newState)
  417. {
  418.   state = newState;
  419.  
  420.   go->ShowWindow(SW_HIDE);
  421.   done->ShowWindow(SW_HIDE);
  422.   deal->ShowWindow(SW_HIDE);
  423.  
  424.   switch (newState) {
  425.     case gsNewGame:
  426.       instructions->SetText("Select 'Game | New' to start a new game.");
  427.       break;
  428.     case gsDeal:
  429.       instructions->SetText("Press the 'deal' button to deal the cards.");
  430.       deal->ShowWindow(SW_SHOW);
  431.       break;
  432.     case gsDiscard:
  433.       instructions->SetText("Discard 2 cards into the crib.");
  434.       done->ShowWindow(SW_SHOW);
  435.       break;
  436.     case gsPegging:
  437.       instructions->SetText("Play a card.  The total of the face values "
  438.                             "may not exceed 31.  If you cannot play a card, "
  439.                             "click the 'go' button.");
  440.       go->ShowWindow(SW_SHOW);
  441.       break;
  442.     case gsPeggingFinish:
  443.       MessageBox("Error!","Error!",MB_OK);
  444. //      instructions->SetText("Play a card.  The total of the face values "
  445. //                            "may not exceed 31.  If you cannot play a card, "
  446. //                            "take your points and continue until all your "
  447. //                            "cards have been played.");
  448. //      take1->ShowWindow(SW_SHOW);
  449. //      take2->ShowWindow(SW_SHOW);
  450.       break;
  451.     case gsPeggingGo:
  452.       instructions->SetText("Play a card.  The total of the face values "
  453.                             "may not exceed 31.  If you cannot play a card, "
  454.                             "click '1 point' or '2 points' to peg your "
  455.                             "'go' points.");
  456. //      take1->ShowWindow(SW_SHOW);
  457. //      take2->ShowWindow(SW_SHOW);
  458.       break;
  459.     case gsGameOver:
  460.       if (board->GetScore(0)==121)
  461.         MessageBox("The computer wins!","Cribbage",MB_OK);
  462.       if (board->GetScore(1)==121)
  463.         MessageBox("You win!!!","Cribbage",MB_OK);
  464.       SetState(gsNewGame);
  465.       break;
  466.   }
  467. }
  468.  
  469. // Deal -- deals the cards.  If it's the computers turn to deal, the
  470. // cards are dealt.  If it's the players turn, the game state is set
  471. // to gsDeal, which waits for the player to click the 'deal' button
  472. //
  473. void TGameWindow::Deal(BOOL prompt) {
  474.   int i,j;
  475.  
  476.   FixDeck();
  477.   deck.Shuffle(5+random(5));
  478.   topCard->Insert(deck.DealCard(), false);
  479.  
  480.   if (dealer==0) {              // computer deals
  481.  
  482.     if (prompt)
  483.       MessageBox("Computers turn to deal.","Cribbage",MB_OK);
  484.  
  485.     crib->MoveWindow(200, 0, 185, 135, true);
  486.     instructions->MoveWindow(200, 280, 185, 135, true);
  487.  
  488.     for (i=0;i<6;i++)
  489.       for (j=1;j>=0;j--) {
  490.         player[j]->Insert(topCard->Remove(), j?true:false);
  491.         topCard->Insert(deck.DealCard(), false);
  492.       }
  493.     ComputerDiscard(dealer);
  494.     SetState(gsDiscard);
  495.   } else {                      // player deals
  496.     crib->MoveWindow(200, 280, 185, 135, true);
  497.     instructions->MoveWindow(200, 0, 185, 135, true);
  498.     SetState(gsDeal);
  499.   }
  500. }
  501.  
  502. // CountPoints -- asks the player to peg points for the card they
  503. // just played.
  504. //
  505. void TGameWindow::CountPoints(TCardGroup*) {
  506.   int actualPoints,points;
  507.  
  508.   // if only one card has been played, no points are
  509.   // possible, so don't pop up the dialog in that case.
  510.  
  511.   if (pegCards->GetCount()>1) {
  512.     actualPoints = ComputePegPoints(1, state==gsPeggingGo);
  513.     if (actualPoints) {
  514.       points = TQuickPointsDialog(this, "Peg points for card played.",
  515.                                    true, actualPoints).Execute();
  516.       if (board->AddToScore(1, points)) {
  517.         SetState(gsGameOver);
  518.         return;
  519.       }
  520.       if (points<actualPoints) {
  521.         TShowPointsDialog(this, TShowPointsDialog::mtMissed,
  522.                            points, actualPoints-points,
  523.                            detail, detailCount).Execute();
  524.         if (board->AddToScore(0, actualPoints-points))
  525.           SetState(gsGameOver);
  526.       }
  527.     }
  528.   }
  529. }
  530.  
  531. // PegCardsSum -- computes the current sum of the face values of
  532. // all the played cards
  533. //
  534. int TGameWindow::PegCardsSum() {
  535.   int i,temp,sum=0;
  536.  
  537.   for (i=0;i<pegCards->GetCount();i++) {
  538.     if ((*pegCards)[i].faceUp)
  539.       temp = FaceValue((*pegCards)[i].rank);
  540.     else
  541.       temp=0;
  542.     sum+=temp;
  543.   }
  544.   return sum;
  545. }
  546.  
  547. // CanClose -- called whenever the app is trying to quit.  If a
  548. // game is in progress, it asks the player if they want to abandon it.
  549. //
  550. bool TGameWindow::CanClose() {
  551.  
  552.   // if a game is in progess, ask the user before closing
  553.  
  554.   if (state!=gsNewGame)
  555.     if (MessageBox("Abandon current game?", "Warning", MB_YESNO)==IDYES)
  556.       return true;
  557.     else
  558.       return false;
  559.  
  560.   // otherwise, it's ok to close
  561.  
  562.   return true;
  563. }
  564.  
  565. // DoneButton -- handler for the 'done' button.  The 'done' button is
  566. // displayed when the game is waiting for the user to discard 2 cards
  567. // into the crib.
  568. //
  569. void TGameWindow::DoneButton() {
  570.  
  571.   // the 'done' button should not be visible unless we're in the
  572.   // gsDiscard state, so if this assertion fails, there is a
  573.   // problem somewhere else in the code which caused the button
  574.   // to be visible at the wrong time.
  575.  
  576.   assert(state==gsDiscard);
  577.  
  578.   // user must have exactly 4 cards left in their hand
  579.  
  580.   if (player[1]->GetCount()!=4) {
  581.     MessageBox("You must discard 2 cards into the crib.", "Error", MB_OK);
  582.   } else {
  583.  
  584.     // turn all the cards in the crib face-down
  585.  
  586.     for (int i=0;i<4;i++)
  587.       crib->FaceUp(i, false);
  588.  
  589.     // the person who didn't deal gets to cut the cards.  the
  590.     // dealer then turns the card over.  If it is the jack,
  591.     // the dealer may take 2 points.
  592.  
  593.     topCard->FaceUp(0, true);
  594.  
  595.     if ((*topCard)[0].rank==11)
  596.       if (dealer==0) {
  597.         MessageBox("Computer takes 2 points for heels.","Cribbage",MB_OK);
  598.         board->AddToScore(0, 2);
  599.       }
  600.       else {
  601.         MessageBox("Player gets 2 points for heels.","Cribbage",MB_OK);
  602.         board->AddToScore(1, 2);
  603.       }
  604.  
  605.     // switch to the game-play state
  606.  
  607.     SetState(gsPegging);
  608.  
  609.     // if we dealt, the computer gets to play the first card.
  610.  
  611.     if (dealer==1)
  612.       ComputerPlayCard();
  613.   }
  614. }
  615.  
  616. // NewGame -- reset the game display and prepare for a new game to start
  617. //
  618. void TGameWindow::NewGame() {
  619.  
  620.   // first check if player wants to abandon current game
  621.  
  622.   if (state!=gsNewGame) {
  623.     int result = MessageBox("Abandon Current Game?", "Warning", MB_YESNO);
  624.     if (result==IDNO) return;
  625.   }
  626.  
  627.   // reset the scoreboard
  628.  
  629.   board->Reset();
  630.  
  631.   // erase the pegcard total, and reset the pegCardOwner array
  632.  
  633.   ResetPegCardDisplay();
  634.  
  635.   // get all the cards back into the deck
  636.  
  637.   FixDeck();
  638.  
  639.   // get the players name, display it on the score board, and
  640.   // on the players card display
  641.  
  642.   int result = TInputDialog(this, "Cribbage",
  643.                              "Enter your name:", playerName, NAME_LEN).Execute();
  644.   if ((result!=IDOK) ||
  645.        (playerName[0]==0))
  646.     strcpy(playerName,"Anonymous");
  647.   board->SetPlayerName(1,playerName);
  648.   player[1]->SetLabel(playerName);
  649.  
  650.   // ask the player to cut a card, to see who deals first
  651.  
  652.   int playerCard=0,
  653.       computerCard=0;
  654.  
  655.   while (deck[playerCard].rank==deck[computerCard].rank) {
  656.  
  657.     // get players cut
  658.  
  659.     playerCard = TCutDeckDialog(this, deck).Execute();
  660.  
  661.     // get a random card for the computer, but don't let
  662.     // the computer choose the same card the player did
  663.  
  664.     do {
  665.       computerCard = random(52);
  666.     } while (computerCard==playerCard);
  667.  
  668.     // show the results
  669.  
  670.     TCutResultDialog(this, deck[playerCard], deck[computerCard]).Execute();
  671.   }
  672.  
  673.   if (deck[playerCard].rank<deck[computerCard].rank)
  674.     dealer=1;
  675.   else
  676.     dealer=0;
  677.  
  678.   Deal(false);
  679. }
  680.  
  681. // PegCard -- adds a card to the pegCards display
  682. //
  683. void TGameWindow::PegCard(TCard* card, int player) {
  684.   int index;
  685.   char temp[10];
  686.  
  687.   // insert the card, face up, and keep track of its index
  688.  
  689.   index = pegCards->Insert(card, true);
  690.  
  691.   // keep track of who owns it
  692.  
  693.   pegCardOwner[index] = player;
  694.  
  695.   // move the cards so they are staggered.  This is so the player can
  696.   // tell the difference between its cards, and the computers cards
  697.  
  698.   pegCards->SetCardPosition(index, TPoint(pegCardPos[index].x, player?15:0));
  699.  
  700.   // figure the new sum, and update the display
  701.  
  702.   wsprintf(temp,"%d",PegCardsSum());
  703.   pegCards->SetLabel(temp);
  704. }
  705.  
  706. // ComputerDiscard -- figure out which 2 cards the computer will
  707. // discard into the crib.  The logic for this should be different
  708. // depending on whether the crib belongs to the computer, or
  709. // the player
  710. //
  711. void TGameWindow::ComputerDiscard(int dealer)  {
  712.  
  713.   // currently, we just discard the first 2 cards in the hand.
  714.   // not very intelligent, but easy to implement.  should be
  715.   // changed later *BBK*
  716.  
  717.   switch (dealer) {
  718.     case 0:  // computers crib
  719.     case 1:  // players crib
  720.       crib->Insert(player[0]->Remove(), false);
  721.       crib->Insert(player[0]->Remove(), false);
  722.       break;
  723.   }
  724. }
  725.  
  726. // DealButton -- handler for the 'deal' button.  When the game state is
  727. // gsDeal, the 'deal' button is visible, and the game is waiting for
  728. // the user to click it to deal.
  729. //
  730. void TGameWindow::DealButton() {
  731.  
  732.   // button should only be visible if we are in the gsDeal state,
  733.   // and it's the players turn to deal
  734.  
  735.   assert((state==gsDeal) && (dealer==1));
  736.  
  737.   // deal the cards
  738.  
  739.   for (int i=0;i<6;i++)
  740.     for (int j=0;j<2;j++) {
  741.       player[j]->Insert(topCard->Remove(), j?true:false);
  742.       topCard->Insert(deck.DealCard(), false);
  743.     }
  744.  
  745.   // let computer discard 2 cards into the crib
  746.  
  747.   ComputerDiscard(dealer);
  748.  
  749.   // wait for user to discard 2 cards
  750.  
  751.   SetState(gsDiscard);
  752. }
  753.  
  754. // CardSelected -- handler for the WM_CARD_SELECTED message, which is
  755. // generated by the TCardDisplay class:
  756. //
  757. //   MSG    - WM_CARD_SELECTED
  758. //   WPARAM - id of the card display control clicked on
  759. //   LPARAM - index of the card selected
  760. //
  761. LRESULT TGameWindow::CardSelected(WPARAM wparam, LPARAM lparam) {
  762.   int group = wparam;
  763.   int index = (int)lparam;
  764.  
  765.   // depending on the game state, clicking on a card does different
  766.   // things
  767.  
  768.   switch (state) {
  769.  
  770.     // in gsDiscard mode, the user can click on a card in their
  771.     // hand to move it to the crib.  Clicking on a faceUp card
  772.     // in the crib (one of their cards), will return it to the
  773.     // players hand.  Clicking on any other cards produces a
  774.     // 'no cheating' message
  775.  
  776.     case gsDiscard:
  777.       if (group==1) { // 1 is the ID of the players cardDisplay control
  778.  
  779.         // clicked on players card
  780.  
  781.         if (player[1]->GetCount()>4)
  782.           crib->Insert(player[1]->Remove(index), true);
  783.         else
  784.           MessageBox("You can only discard two cards.  Click on\n"
  785.                       "a card in the crib to return it to your hand.",
  786.                       "Cribbage", MB_OK);
  787.       } else
  788.  
  789.         // clicked on crib card.  make sure it is one of the players
  790.         // cards (player cards are face up, computer cards are face
  791.         // down), and then move it back to the players hand
  792.  
  793.         if (group==2) {  // crib
  794.           if ((*crib)[index].faceUp)
  795.             player[1]->Insert(crib->Remove(index), true);
  796.           else
  797.             MessageBox("That's not your card!", "No Cheating!", MB_OK);
  798.         }
  799.       break;
  800.  
  801.     // during the game play
  802.  
  803.     case gsPegging:
  804.       if (group==1) {
  805.  
  806.         // players card was selected
  807.  
  808.         int currentSum,faceValue;
  809.         currentSum=PegCardsSum();
  810.  
  811.         // don't allow the card to be played if it would cause the
  812.         // sum of the face values to exceed 31
  813.  
  814.         faceValue = FaceValue((*player[1])[index].rank);
  815.  
  816.         if (currentSum+faceValue>31) {
  817.           MessageBox("Playing that card would exceed 31.", "Cribbage", MB_OK);
  818.           return true;
  819.         }
  820.  
  821.         // insert the card into the display
  822.  
  823.         PegCard(player[1]->Remove(index), 1);
  824.  
  825.         // allow the player to count points
  826.  
  827.         CountPoints(pegCards);
  828.  
  829.         // if all cards have been played
  830.  
  831.         if (pegCards->GetCount()==8) {
  832.           ShowPoints();                // count hands
  833.           if (GameOver()) {
  834.             SetState(gsGameOver);
  835.             return true;
  836.           }
  837.           dealer = (dealer+1)%2;       // next dealer
  838.           Deal(true);                // start new hand
  839.  
  840.         } else {                       // otherwise
  841.           if (PegCardsSum()==31)
  842.             TurnOverPegCards();
  843.           ComputerPlayCard();          // let the computer play a card
  844.         }
  845.       }
  846.       break;
  847.     case gsPeggingGo:  // computer has said 'go'
  848.       if (group==1) {
  849.  
  850.         // don't allow the card to be played if it would cause the
  851.         // sum of the face values to exceed 31
  852.  
  853.         int faceValue = FaceValue((*player[1])[index].rank);
  854.  
  855.         if ((PegCardsSum()+faceValue)>31) {
  856.           MessageBox("Playing that card would exceed 31.", "Cribbage", MB_OK);
  857.           return true;
  858.         }
  859.  
  860.         // insert the card into the display
  861.  
  862.         PegCard(player[1]->Remove(index), 1);
  863.  
  864.         // allow the player to count points
  865.  
  866.         CountPoints(pegCards);
  867.  
  868.         // if the sum is 31, or the player has no other playable
  869.         // cards, turn over the cards and continue by having the
  870.         // computer play a card
  871.  
  872.         if ((PegCardsSum()==31) ||
  873.              (PlayableCards(player[1])==-1)) {
  874.           TurnOverPegCards();
  875.           SetState(gsPegging);
  876.           if (player[0]->GetCount()>0) {
  877.             ComputerPlayCard();
  878.             return true;
  879.           }
  880.         }
  881.  
  882.         if (pegCards->GetCount()==8) {
  883.           ShowPoints();
  884.           if (GameOver()) {
  885.             SetState(gsGameOver);
  886.             return true;
  887.           }
  888.           dealer=(dealer+1)%2;
  889.           Deal(true);
  890.         }
  891.       }
  892.       break;
  893.   }
  894.   return true;
  895. }
  896.  
  897. // PlayableCards -- given a group of cards, determines which cards
  898. // can be played without exceeding 31.  The 'playable' parameter is
  899. // filled with values that state whether each card is playable or
  900. // not.  The function also returns the index of the first playable
  901. // card, or -1 if none are playable.
  902. //
  903. // note: the parameter 'playable' can be 0, in which case the
  904. // function only computes the first playable card.
  905. //
  906. int TGameWindow::PlayableCards(TCardGroup* cards, BOOL *playable) {
  907.   int i,first,pegSum = PegCardsSum();
  908.  
  909.   first=-1;
  910.  
  911.   for (i=0;i<cards->GetCount();i++) {
  912.     if (playable)
  913.       playable[i]=false;
  914.     if ((*cards)[i].rank+pegSum<=31) {
  915.       if (playable)
  916.         playable[i]=true;
  917.       if (first==-1)
  918.         first=i;
  919.     }
  920.   }
  921.   return first;
  922. }
  923.  
  924. void TGameWindow::TurnOverPegCards() {
  925.   int i;
  926.   for (i=0;i<pegCards->GetCount();i++)
  927.     pegCards->FaceUp(i, false);
  928. }
  929.  
  930. // ComputePegPoints -- compute the points generated by the last
  931. // card played
  932. //
  933. int TGameWindow::ComputePegPoints(int cardPlayer, BOOL goInEffect) {
  934.   int count,totalcount,total,largestRun,i,j,k;
  935.   int currentValue,transitionCount,pairCount,firstFaceUp;
  936.   int rank[8],hittest[13];
  937.   char temp[30];
  938.  
  939.   total=0;
  940.   detailCount=0;
  941.  
  942.   totalcount = pegCards->GetCount();
  943.  
  944.   // find the first face-up card
  945.  
  946.   firstFaceUp=0;
  947.   while ((firstFaceUp<totalcount) && ((*pegCards)[firstFaceUp].faceUp==false))
  948.     firstFaceUp++;
  949.  
  950.   // if the sum = 15, 2 points
  951.  
  952.   if (PegCardsSum()==15) {
  953.     total+=2;
  954.     detail[detailCount][0]=0;
  955.     for (i=firstFaceUp;i<pegCards->GetCount();i++)
  956.       strcat(detail[detailCount],(*pegCards)[i].Stringify());
  957.     strcat(detail[detailCount++],"\t(15)\t2 pts");
  958.   }
  959.  
  960.   // if sum == 31, 2 points (if no go is in effect)
  961.  
  962.   if ((PegCardsSum()==31)&&(!goInEffect)) {
  963.     total+=2;
  964.     detail[detailCount][0]=0;
  965.     for (i=firstFaceUp;i<pegCards->GetCount();i++)
  966.       strcat(detail[detailCount],(*pegCards)[i].Stringify());
  967.     strcat(detail[detailCount++],"\t(31)\t2 pts");
  968.   }
  969.  
  970.   // get the ranks of all the face-up cards
  971.  
  972.   count=0;
  973.   i=firstFaceUp;
  974.   while (i<totalcount)
  975.     rank[count++]=(*pegCards)[i++].rank;
  976.  
  977.   // if there are 3 or more cards, check for runs
  978.  
  979.   largestRun=0;
  980.   if (count>=3) {
  981.     for (i=0;i<(count-3+1);i++) {
  982.       for (k=0;k<13;k++)
  983.         hittest[k]=0;
  984.       for (j=i;j<count;j++)
  985.         hittest[rank[j]-1]++;
  986.  
  987.       currentValue=0;
  988.       transitionCount=0;
  989.       for (j=0;j<13;j++) {
  990.         if (hittest[j]!=currentValue) {
  991.           transitionCount++;
  992.           currentValue=hittest[j];
  993.           if (currentValue>1)
  994.             transitionCount=10;
  995.         }
  996.       }
  997.       if ((transitionCount<=2) && (largestRun==0))
  998.         largestRun = (count-i);
  999.     }
  1000.   }
  1001.  
  1002.   total+=largestRun;
  1003.   if (largestRun) {
  1004.     detail[detailCount][0]=0;
  1005.     for (i=totalcount-largestRun;i<totalcount;i++)
  1006.       strcat(detail[detailCount],(*pegCards)[i].Stringify());
  1007.     wsprintf(temp,"\t%d-card run\t%d pts",largestRun,largestRun);
  1008.     strcat(detail[detailCount++],temp);
  1009.   }
  1010.  
  1011.   // if there are more than 2 cards, check for pairs
  1012.  
  1013.   if (count>=2) {
  1014.     currentValue=rank[count-1];
  1015.     pairCount=0;
  1016.     i=count-2;
  1017.     while ((i>=0)&&(rank[i]==currentValue)) {
  1018.       pairCount++;
  1019.       i--;
  1020.     }
  1021.  
  1022.     switch (pairCount) {
  1023.       case 1:
  1024.         detail[detailCount][0]=0;
  1025.         for (i=totalcount-1;i>=totalcount-2;i--)
  1026.           strcat(detail[detailCount],(*pegCards)[i].Stringify());
  1027.         strcat(detail[detailCount++],"\t1 pair\t2 pts");
  1028.         total+=2;
  1029.         break;
  1030.       case 2:
  1031.         detail[detailCount][0]=0;
  1032.         for (i=totalcount-1;i>=totalcount-3;i--)
  1033.           strcat(detail[detailCount],(*pegCards)[i].Stringify());
  1034.         strcat(detail[detailCount++],"\t3 pair\t6 pts");
  1035.         total+=6;
  1036.         break;
  1037.       case 3:
  1038.         detail[detailCount][0]=0;
  1039.         for (i=totalcount-1;i>=totalcount-4;i--)
  1040.           strcat(detail[detailCount],(*pegCards)[i].Stringify());
  1041.         strcat(detail[detailCount++],"\t6 pair\t12 pts");
  1042.         total+=12;
  1043.         break;
  1044.     }
  1045.   }
  1046.  
  1047.   // if all cards have been played, add 1 point for last card.
  1048.  
  1049.   if ((!goInEffect)&&(pegCards->GetCount()==8)) {
  1050.     total++;
  1051.     wsprintf(detail[detailCount++],"\tlast card\t1 pt");
  1052.   }
  1053.  
  1054.   // if a go is in effect, check to see if the player that just played
  1055.   // can play another card.  If not, then they can take a point for the
  1056.   // go
  1057.  
  1058.   if ((goInEffect) &&
  1059.        (PlayableCards(player[cardPlayer])==-1)) {
  1060.     if (PegCardsSum()==31) {
  1061.       total+=2;
  1062.       wsprintf(detail[detailCount++],"\tgo (31)\t2 pts");
  1063.     } else {
  1064.       total++;
  1065.       wsprintf(detail[detailCount++],"\tgo\t1 pt");
  1066.     }
  1067.   }
  1068.  
  1069.   return total;
  1070. }
  1071.  
  1072. void TGameWindow::ScoreComputerPegPoints() {
  1073.   int points = ComputePegPoints(0, false);
  1074.  
  1075.   if (points) {
  1076.     TShowPointsDialog(this, TShowPointsDialog::mtPegging,
  1077.                        points, 0, detail, detailCount).Execute();
  1078.     if (board->AddToScore(0, points))
  1079.       SetState(gsGameOver);
  1080.   }
  1081. }
  1082.  
  1083. // ComputerPlayPegCard -- select a single card to play.  If the parameter
  1084. // 'goInEffect' is true, and the computer cannot play a card, the computer
  1085. // will take 1 or 2 points (2 if the sum is equal to 31).
  1086. //
  1087. // if 'goInEffect' is true, the return value indicates whether the
  1088. // computer took points for the go.
  1089. //
  1090. // if 'goInEffect' is false, the return value indicates whether the
  1091. // computer played a card or not.
  1092. //
  1093. BOOL TGameWindow::ComputerPlayPegCard(BOOL goInEffect) {
  1094.   int playableCard;
  1095.   BOOL done;
  1096.  
  1097.   done=false;
  1098.   playableCard = PlayableCards(player[0], 0);
  1099.  
  1100.   if (playableCard>=0) {
  1101.     PegCard(player[0]->Remove(playableCard), 0);
  1102.     ScoreComputerPegPoints();
  1103.     if (PegCardsSum()==31)
  1104.       TurnOverPegCards();
  1105.     return true;
  1106.   }
  1107.  
  1108.   if (goInEffect) {
  1109.     done=true;
  1110.     if (PegCardsSum()==31) {
  1111.       MessageBox("Computer takes 2 points for 31.", "Cribbage", MB_OK);
  1112.       TurnOverPegCards();
  1113.       board->AddToScore(0, 2);
  1114.     }
  1115.     else {
  1116.       MessageBox("Computer takes 1 point.", "Cribbage", MB_OK);
  1117.       TurnOverPegCards();
  1118.       board->AddToScore(0, 1);
  1119.     }
  1120.   } // else done=false, which means the computer didn't play a card
  1121.   return done;
  1122. }
  1123.  
  1124. // ComputerPlayCard -- plays one or more cards from the computers hand,
  1125. // depending on several things:
  1126. //
  1127. //   - whether the player said 'go' (goInEffect parameter == true)
  1128. //   - whether the player has any cards left
  1129. //
  1130. void TGameWindow::ComputerPlayCard(BOOL goInEffect) {
  1131.   BOOL done;
  1132.  
  1133.   // if player has not said 'go', so just play one card
  1134.  
  1135.   if (!goInEffect) {
  1136.  
  1137.     // if computer doesn't have any cards, then just return
  1138.  
  1139.     if (player[0]->GetCount()==0)
  1140.       return;
  1141.  
  1142.     // have the computer play a card.  If it couldn't, then
  1143.     // the computer says 'go'.
  1144.  
  1145.     if (!ComputerPlayPegCard(goInEffect)) {
  1146.       int playableCard = PlayableCards(player[1], 0);
  1147.  
  1148.       // show a dialog that says 'go', and depending on whether
  1149.       // the player can play a card, either put a button that
  1150.       // says 'ok', or 'take 1 point'.
  1151.  
  1152.       TGoDialog(this, (playableCard!=-1)).Execute();
  1153.  
  1154.       // if the player has a playable card, switch back to
  1155.       // gsPeggingGo state
  1156.  
  1157.       if (playableCard!=-1)
  1158.         SetState(gsPeggingGo);
  1159.       else {
  1160.  
  1161.       // otherwise, since the computer said go, it's the computers
  1162.       // turn to play.
  1163.  
  1164.         board->AddToScore(1, 1);
  1165.         TurnOverPegCards();
  1166.  
  1167.         ComputerPlayCard();
  1168.       }
  1169.     }
  1170.   }
  1171.  
  1172.   // otherwise the player has said 'go', so keep playing cards until
  1173.   // you hit 31, or you run out of cards.
  1174.  
  1175.   else {
  1176.  
  1177.     // if the player is out of cards, keep playing until the
  1178.     // computer is out
  1179.  
  1180.     if (player[1]->GetCount()==0) {
  1181.       while (player[0]->GetCount()>0)
  1182.         ComputerPlayPegCard(goInEffect);
  1183.       ShowPoints();
  1184.       if (GameOver()) {
  1185.         SetState(gsGameOver);
  1186.         return;
  1187.       }
  1188.       dealer=(dealer+1)%2;
  1189.       Deal(true);
  1190.     }
  1191.  
  1192.     // otherwise, play until the computer hits 31, then return
  1193.     // to normal pegging
  1194.  
  1195.     else {
  1196.       done=false;
  1197.       while (!done)
  1198.         done = ComputerPlayPegCard(goInEffect);
  1199.       SetState(gsPegging);
  1200.     }
  1201.     return;
  1202.   }
  1203. }
  1204.  
  1205. void TGameWindow::GoButton() {
  1206.   int i,pegSum,temp;
  1207.   pegSum=0;
  1208.   for (i=0;i<pegCards->GetCount();i++) {
  1209.     if ((*pegCards)[i].faceUp)
  1210.       temp = (*pegCards)[i].rank;
  1211.     else temp=0;
  1212.     if (temp>9) temp=10;
  1213.     pegSum+=temp;
  1214.   }
  1215.   for (i=0;i<player[1]->GetCount();i++)
  1216.     if (player[1]->operator[](i).rank+pegSum<=31) {
  1217.       MessageBox("You must play a card if it is playable.",
  1218.                  "Cribbage",MB_OK);
  1219.       return;
  1220.     }
  1221.   ComputerPlayCard(true);
  1222. }
  1223.  
  1224. //
  1225. // FixDeck -- removes all the cards from the game board, and returns
  1226. // them to the deck
  1227. //
  1228. void TGameWindow::FixDeck()
  1229. {
  1230.   deck.Insert(player[0]);
  1231.   deck.Insert(player[1]);
  1232.   deck.Insert(pegCards);
  1233.   deck.Insert(crib);
  1234.   deck.Insert(topCard);
  1235. }
  1236.  
  1237. // TGameWindow -- constructor.  Builds the main game window,
  1238. // inserts all the card display controls, the game board, the buttons,
  1239. // and the instruction window.  Also, initializes the deck of cards.
  1240. //
  1241.  
  1242. TGameWindow::TGameWindow(): TWindow(0,0,0) {
  1243.   char encodedDeck[53];
  1244.  
  1245.   // allocate memory for the detailed point lists
  1246.  
  1247.   for (int i=0;i<DETAIL_MAXCOUNT;i++)
  1248.     detail[i] = new char[DETAIL_MAXLEN];
  1249.  
  1250.   // get the saved deck, and back style from the .INI file
  1251.  
  1252.   cardBackStyle = GetPrivateProfileInt("deck","backstyle",0,IniFilename);
  1253.   GetPrivateProfileString("game","playername","Anonymous",playerName,NAME_LEN,IniFilename);
  1254.   GetPrivateProfileString("deck","thecards","",encodedDeck,53,IniFilename);
  1255.   if (encodedDeck[0]!=0)
  1256.     if (!deck.DecodeDeck(encodedDeck)) {
  1257.       MessageBox("Saved deck is corrupted, using new deck.", "Warning", MB_OK);
  1258.       deck.Initialize(cardBackStyle);
  1259.     }
  1260.     else deck.ResetBackStyle(cardBackStyle);
  1261.  
  1262.   // set window size
  1263.  
  1264.   Attr.W = 605;
  1265.   Attr.H = 410;
  1266.  
  1267.   // create all the controls
  1268.  
  1269.   player[0] = new TCardDisplay(this, 0, 0, 0, 185, 135, 10,
  1270.                                 6, handCardPos, true, "Computer", TPoint(20,2));
  1271.  
  1272.   player[1] = new TCardDisplay(this, 1, 0, 280, 185, 135, 10,
  1273.                                 6, handCardPos, true, "Human", TPoint(20,2));
  1274.  
  1275.   crib = new TCardDisplay(this, 2, 200, 0, 185, 135, 10,
  1276.                            4, cribCardPos, true, "Crib", TPoint(140,60));
  1277.  
  1278.   pegCards = new TCardDisplay(this, 3, 5, 150, 200, 125, 0,
  1279.                                8, pegCardPos, false, "", TPoint(0,50));
  1280.  
  1281.   topCard = new TCardDisplay(this, 4, 305, 155, 71, 95, 0,
  1282.                               1, topCardPos);
  1283.  
  1284.   instructions = new TStatic(this, 6, "", 200, 280, 185, 135);
  1285.  
  1286.   board = new TCribbageBoard(this, 400, 5);
  1287.   board->SetPlayerName(0,"Computer");
  1288.   board->SetPlayerName(1,"Human");
  1289.   deal = new TButton(this, CM_DEAL_BUTTON, "Deal", 210, 195, 70, 30);
  1290.   go =   new TButton(this, CM_GO_BUTTON,   "Go",   210, 195, 70, 30);
  1291.   done = new TButton(this, CM_DONE_BUTTON, "Done", 210, 195, 70, 30);
  1292.  
  1293.   // initialize the game state, to wait for a new game to be started
  1294.   //
  1295.   SetState(gsNewGame);
  1296.  
  1297.   // set the window background to be green
  1298.   //
  1299.   SetBkgndColor(TColor(0, 128, 0));
  1300. }
  1301.  
  1302. //
  1303. // ~TGameWindow -- destructor.  Delete the brush we created, get all
  1304. // the cards back into the deck, and save the deck into the .INI file
  1305. //
  1306. TGameWindow::~TGameWindow()
  1307. {
  1308.   WritePrivateProfileString("game","playername",playerName,IniFilename);
  1309.   for (int i = 0; i < DETAIL_MAXCOUNT; i++)
  1310.     delete[] detail[i];
  1311.  
  1312.   FixDeck();
  1313.   WritePrivateProfileString("deck","thecards",deck.EncodeDeck(),IniFilename);
  1314. }
  1315.  
  1316. //
  1317. // SetupWindow
  1318. //
  1319. void TGameWindow::SetupWindow()
  1320. {
  1321.   try {
  1322.  
  1323.     TWindow::SetupWindow();
  1324.   }
  1325.   catch (TXOwl msg) {
  1326.     MessageBox(msg.why().c_str(), "msg");
  1327.   }
  1328.  
  1329.   // set the intial state, to wait for a new game
  1330.   //
  1331.   SetState(gsNewGame);
  1332.  
  1333.   // demo code
  1334.   //  TCard *temp = deck.DealCard();
  1335.   //  topCard->Insert(temp, true);
  1336.  
  1337.   // Actual game code
  1338.   //
  1339.   topCard->Insert(deck.DealCard(), false);
  1340. }
  1341.  
  1342. // Paint -- paints the game board.  Most of the painting is done by
  1343. // the child windows, but we have a single bitmap (the deck of cards)
  1344. // which must be drawn.
  1345. //
  1346. void TGameWindow::Paint(TDC& dc, bool, TRect&) {
  1347.   TBitmap deck(_hInstance, DECK);
  1348.   TMemoryDC memDC(dc);
  1349.   memDC.SelectObject(deck);
  1350.   dc.BitBlt(290, 154, 88, 112, memDC, 0, 0, SRCCOPY);
  1351. }
  1352.  
  1353. // TCribbageApp -- the main application.  Just the basics here, setup
  1354. // a frame window (without a sizeable border).  Assign our menu and
  1355. // icon to it.
  1356. //
  1357. class TCribbageApp: public TApplication {
  1358.   public:
  1359.     TCribbageApp(): TApplication() {
  1360.       randomize();
  1361.       EnableCtl3d();
  1362.     }
  1363.     void InitMainWindow() {
  1364.       TFrameWindow *fw;
  1365.       int          width,height;
  1366.  
  1367.       // get the current video resolution
  1368.       //
  1369.       width = TScreenDC().GetDeviceCaps(HORZRES);
  1370.       height = TScreenDC().GetDeviceCaps(VERTRES);
  1371.  
  1372.       fw = new TFrameWindow(0, "Turbo Cribbage", new TGameWindow, TRUE);
  1373.       fw->Attr.Style = WS_OVERLAPPED | WS_CAPTION |
  1374.                        WS_SYSMENU | WS_MINIMIZEBOX;
  1375.  
  1376.       // center the window on the screen.  since these calculations
  1377.       // are based on the client window size, the window won't be
  1378.       // entirely centered, but it's close enough.
  1379.       //
  1380.       fw->Attr.X = (width-605)/2;
  1381.       fw->Attr.Y = (height-410)/2-20;
  1382.  
  1383.       // assign the menu and icon to our framewindow
  1384.       //
  1385.       fw->AssignMenu(MENU_1);
  1386.       fw->SetIcon(this, ICON_1);
  1387.  
  1388.       SetMainWindow(fw);
  1389.     }
  1390. };
  1391.  
  1392. int OwlMain(int, char *[]) {
  1393.   TBIVbxLibrary vbxLib;           // necessary for VBX controls to work
  1394.   return TCribbageApp().Run();    // play cribbage!
  1395. }
  1396.